/*
* Copyright (c) 2008 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_THREADPOOL_H
#define M_THREADPOOL_H

#include "singleton.h"
#include "atomic.h"
#include "refptr.h"
#include "thread.h"

#include "lfqueue.h"
#include "lffreelist.h"

#include "event.h"

#include <list>

namespace Engine
{
	/**
	*   Base interface for task.
	*/
	class BaseTask
	{
	public:
		friend class TaskExecutor;

		BaseTask()
			:m_runing(0)
		{
			m_finished.Signal();
		}
		/**
		*   Execute task code.
		*/
		virtual void Run() = 0;
		virtual ~BaseTask(){}

		/**
		*   Return true is task still execte.
		*/
		bool IsRuning() const
		{
			long val = AtomicExchange(&m_runing, m_runing);
			return val == 1 ? true : false;
		}

		/**
		*   Set task state(running or not).
		*/
		void SetRuning(bool val)
		{
			AtomicExchange(&m_runing, val);
			if(val)
				m_finished.Reset();
			else
				m_finished.Signal();
		}

		/**
		*   Wait while task running
		*/
		void Wait()
		{
			if(IsRuning())
				m_finished.Wait(INFINITE);
		}

	private:
		mutable volatile long m_runing;
		Event m_finished;
	};


	class ThreadPool;
	/**
	*   Implementation of thread for task executing
	*/
	class TaskExecutor
	{
	public:
		TaskExecutor(int){}
		bool Task(unsigned long*);

		BaseTask* task;
	};

    /**
    *   Thread pool implementation.
    */
	class ThreadPool: public Singleton<ThreadPool>
    {
    public:
		friend class TaskExecutor;

		typedef RefPtr<Thread<TaskExecutor> > ThreadPtr;
		typedef Thread<TaskExecutor>* ThreadRawPtr;

		typedef LockFree::FreeList<LockFree::node<ThreadRawPtr > > ThreadNodePool;
		typedef LockFree::Queue<ThreadRawPtr> ThreadQueue;

		typedef std::list<ThreadPtr> ThreadList;

        /**
        *   Constructor.
        *   @param num number of threads.
		*   @param maxNum maximum number of threads
        */
        ThreadPool(unsigned int num, unsigned int maxNum);

        /**
        *   Destructor.
        */
        ~ThreadPool();

        /**
        *   Place new task to pool.
        */
        void Run(RefPtr<BaseTask> task);

		/**
		*   Change number of active threads.
		*/
		void SetThreadsNum(unsigned int num);

		/**
		*   Return current number of threads
		*/
		unsigned int GetThreadsNum() const;

    private:

		/**
		*   Clear free thread queue.
		*/
		void FreeThreadsQueue(unsigned int num);

		/**
		*   Return free thread for task executing.
		*/
		ThreadRawPtr ReserveThread();

		/**
		*   Return thread to queue
		*/
		void ReturnThread(ThreadRawPtr th);

        //Hidden methods

        ThreadPool(const ThreadPool&);

        ThreadPool& operator=(const ThreadPool&);

    private:
		ThreadNodePool m_threadPool;     ///< Object for allocating new thread nodes.
		ThreadQueue m_freeThreads; ///< Free threads.
		ThreadList m_threads; ///< all created threads.
		unsigned int m_threadsCount;
    };
}

#endif

